#include "SQLObjectImpl.h"
#include "../visitor/SQLASTVisitor.h"
#include "../visitor/SQLASTOutputVisitor.h"
#include "SQLCommentHint.h"
#include "SQLDbTypedObject.h"
#include "../../Exception/IllegalArgumentException.h"
#include "../../utils/instanceof.h"
#include "../../DbType.h"
#include "../dialect/oracle/ast/OracleSQLObject.h"
#include "../dialect/mysql/ast/MySqlObject.h"
#include "../SQLUtils.h"

// string_ptr  SQLObjectImpl::buf ("xxx:");
SQLObjectImpl::SQLObjectImpl()
    // : buf(make_string_ptr(" in SQLObjectImpl class, "))
{
  // SQLObjectImpl::SQLObjectImpl() {
  // SQLObjectImpl::SQLObjectImpl() {
}

SQLObjectImpl::~SQLObjectImpl()
{

  // for(std::map<string_ptr , Object_ptr >::iterator it = attributes.begin(); it != attributes.end(); ++it)
  //{
  // delete it->second;
  //}
}

void SQLObjectImpl::accept(SQLASTVisitor_ptr visitor)
{

  if (visitor == NULL)
  {
    throw new IllegalArgumentException();
  }

  visitor->preVisit(SharedObject(SQLObjectImpl));

  accept0(visitor);

  visitor->postVisit(SharedObject(SQLObjectImpl));
}

void SQLObjectImpl::acceptChild(SQLASTVisitor_ptr visitor, SQLObject_list_ptr children)
{
  if (children->empty())
  {
    return;
  }

  std::list<SQLObject_ptr>::iterator iStart = children->begin();
  std::list<SQLObject_ptr>::iterator iEnd = children->end();
  std::list<SQLObject_ptr>::iterator it;
  for (it = iStart; it != iEnd; ++it)
  {
    acceptChild(visitor, *it);
  }
}

void SQLObjectImpl::acceptChild(SQLASTVisitor_ptr visitor, SQLObject_ptr child)
{
  if (child == nullptr)
  {
    return;
  }

  child->accept(visitor);
}

void SQLObjectImpl::output(std::stringstream *theBuf)
{
  DbType_ptr dbType = nullptr;
  if (instanceof <SQLObjectImpl, OracleSQLObject>(this))
  {
    dbType = DbType_ptr(new DbType(&DbType::oracle));
  }
  else if (instanceof <SQLObjectImpl, MySqlObject>(this))
  {
    dbType = DbType_ptr(new DbType(&DbType::mysql));
  }
  // else if (instanceof <SQLObjectImpl, PGSQLObject>(this))
  // {
  //   dbType = DbType_ptr(new DbType(&DbType::postgresql));
  // }
  else if (instanceof <SQLObjectImpl, SQLDbTypedObject>(this))
  {
    dbType = (dynamic_cast<SQLDbTypedObject *>(this))->getDbType();
  }

  accept(SQLUtils::createOutputVisitor(&buf, dbType));
}

string_ptr SQLObjectImpl::toString()
{
  // std::cout << buf << std::endl;
  // exit(1);
  // buf = make_string_ptr("");
  output(&buf);
  return make_string_ptr(buf.str());

  // string_ptr  *x = new string_ptr ();
  // output(*x);
  // return *x;
}

SQLObject_ptr SQLObjectImpl::getParent()
{
  return parent;
}

void SQLObjectImpl::setParent(SQLObject_ptr theParent)
{
  parent = theParent;
}

std::shared_ptr<std::map<std::string, Object_ptr>> SQLObjectImpl::getAttributes()
{
  if (attributes == nullptr)
  {
    attributes = std::shared_ptr<std::map<std::string, Object_ptr>>();
  }

  return attributes;
}

// Object_ptr SQLObjectImpl::getAttribute(string_ptr name)
// {
//   return attributes->find(name)->second;
// }

// Object_ptr SQLObjectImpl::getAttribute(string_ptr name)
// {
//   // if (attributes == NULL) {
//   // return NULL;
//   //}

//   // test is empty is unneccessary??
//   // map<string_ptr ,Object &>::const_iterator it = attributes.find(name);
//   // if (it != attributes.end())
//   //{
//   // return attributes.find(name)->second;
//   //}

//   return attributes->find(name)->second;
// }

// void SQLObjectImpl::putAttribute(string_ptr name, Object_ptr value)
// {
//   // if (attributes == NULL) {
//   // attributes = new Hashstd::map<string_ptr , Object>(1);
//   //}

//   attributes->insert(std::make_pair(name, value));
//   // attributes.put(name, value);
// }


std::shared_ptr<std::map<std::string, Object_ptr>> SQLObjectImpl::getAttributesDirect()
{
  return attributes;
}

// string_ptr SQLObjectImpl::toString()
//{
// static string_ptr  x = "in SQLObjectImpl class";
// return x;
//}

SQLCommentHint_ptr SQLObjectImpl::getHint()
{
  return hint;
}

void SQLObjectImpl::setHint(SQLCommentHint_ptr hint)
{
  this->hint = hint;
}

string_ptr SQLObjectImpl::getClass()
{
  return make_string_ptr("SQLObjectImpl");
}